use crate::token::Token;
// 词法分析器，先从处理简单符号开始：+ - * / 整数
// 扫描到的词存储在Token中
pub struct Scanner {
    // 代码行数
    line: u32,
    // 代码文本
    code: Vec<char>,
    // 最后一个字符
    back: Option<char>,
    // 扫描到的最后一个字符下标
    last_index: usize,
}


impl Scanner {
    pub fn new(code: &str) -> Scanner {
        Scanner {
            line: 1,
            code: code.chars().collect(),
            back: None,
            last_index: 0,
        }
    }

    // 获取下一个字符,根据字符挨个处理，last存储要回退的字符，因为在扫描多个字节的token时，会扫到下个token的第一个字符才能判断其结束，所以需要回退多扫描的字符。
    // 返回None则说明已经到结尾了
    fn next(&mut self) -> Option<char> {
        match self.back {
            // back空的时候说明不需要回退
            None => {
                if self.last_index >= self.code.len() {
                    return None;
                }
                let c = self.code[self.last_index];
                if c == '\n' {
                    self.line += 1;
                }
                self.last_index += 1;
                return Some(c);
            }

            _ => {
                // back里有值，说明存储了扫描上个token时，扫描超过的那个字符
                let c = self.back.unwrap();
                self.back = None;
                return Some(c);
            }
        }
    }

    // 跳过空格并取得下一个字符
    fn skip(&mut self) -> Option<char> {
        let mut c = self.next();
        if c == None {
            return None;
        }
        while (c.unwrap() == ' ') || (c.unwrap() == '\n') || (c.unwrap() == '\t') || (c.unwrap() == '\r') {
            c = self.next();
            if c == None {
                return None;
            }
        }
        c
    }

    // 扫描所有的token
    pub fn scan(&mut self) -> Vec<Token> {
        let mut tokens = Vec::new();
        let mut token = self.scan_token();
        while token.is_some() {
            tokens.push(token.unwrap());
            token = self.scan_token();
        }
        tokens
    }

    // 扫描有意义的token，跳过空格
    fn scan_token(&mut self) -> Option<Token> {
        let c = self.skip();

        match c {
            Some('+') => Some(Token::Add),
            Some('-') => Some(Token::Substract),
            Some('*') => Some(Token::Multiply),
            Some('/') => Some(Token::Divide),
            None => None,
            _ => {
                if c.unwrap().is_digit(10) {
                    let num = self.scan_int(c);
                    if num == None {
                        return None;
                    }
                    let token_intlit = Token::Integer(num.unwrap());
                    return Some(token_intlit);
                } else {
                    panic!("error at line: {}.", self.line);
                }
            }
        }
    }

    // 扫描整数
    fn scan_int(&mut self, mut c: Option<char>) -> Option<i32> {
        let mut value = 0;
        while c.unwrap().is_digit(10) {
            let num = c.unwrap().to_digit(10);
            value = value * 10 + (num.unwrap() as i32);
            c = self.next();
            if c == None {
                return Some(value);
            }
        }
        self.back = c;
        Some(value)
    }

    pub fn line(&self) -> u32 {
        self.line
    }
}
